import unittest
import sys
import os
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
from utils.compat import set_debuglevel
set_debuglevel(-2) # disable verbosity

class UtilsCommandsTests(unittest.TestCase):
    def setUp(self):
        from utils import commands
        self.cmd_manager = commands.CommandManager()

    def test_server_command(self):
        def my_func(args):
            """
            MyDescription
            """
            pass
        self.cmd_manager.server_command(my_func)
        self.assertEqual('my_func', self.cmd_manager.commands['server'][0])

    def test_client_command(self):
        def my_func(args):
            """
            MyDescription
            """
            pass
        self.cmd_manager.client_command(my_func)
        self.assertEqual('my_func', self.cmd_manager.commands['client'][0])

    def test_say_command(self):
        def my_func(args):
            """
            MyDescription
            """
            pass
        self.cmd_manager.say_command(my_func)
        self.assertEqual('my_func', self.cmd_manager.commands['say'][0])
        
        
class UtilsDelayTests(unittest.TestCase):
    def setUp(self):
        from utils import delay
        self.delay = delay
        delay_manager = delay.DelayManager('test')
        self.delayer = delay_manager.get_reference(self)
        
    def __my_loop_func(self):
        self.num += 1
        if self.num == 10:
            raise self.delay.StopLoop
        
    def test_loop(self):
        self.num = 0
        self.loop = self.delayer.loop(1, self.__my_loop_func)
        self.assertEqual(10, self.num)
        
    def __delay_func(self):
        self.pony = True
        
    def test_delay(self):
        self.pony = False
        self.delayer.delay(1, self.__delay_func)
        self.assertTrue(self.pony)
        
        
class UtilsWebTests(unittest.TestCase):
    def setUp(self):
        from utils import web
        import urllib
        self.web = web
        self.value = urllib.urlopen('http://ip.ojii.ch').read()
        
    def test_wget_sync(self):
        backend = self.web.WgetBackend()
        response = backend.request('http://ip.ojii.ch')
        self.assertEqual(response.data, self.value)
        
    def __wget_async_cb(self, response):
        self.wget_response = response
        
    def test_wget_async(self):
        backend = self.web.WgetBackend()
        backend.async_request('http://ip.ojii.ch',
                              self.__wget_async_cb)
        self.assertEqual(self.wget_response.data, self.value)
        
    def test_curl_sync(self):
        backend = self.web.CurlBackend()
        response = backend.request('http://ip.ojii.ch')
        self.assertEqual(response.data, self.value)
        
    def __curl_async_cb(self, response):
        self.curl_response = response
        
    def test_curl_async(self):
        backend = self.web.CurlBackend()
        backend.async_request('http://ip.ojii.ch',
                              self.__curl_async_cb)
        self.assertEqual(self.curl_response.data, self.value)
        
    def test_urllib_sync(self):
        backend = self.web.UrllibBackend()
        response = backend.request('http://ip.ojii.ch')
        self.assertEqual(response.data, self.value)
        
    def __urllib_async_cb(self, response):
        self._urllib_response = response
        
    def test_urllib_async(self):
        backend = self.web.UrllibBackend()
        class NOTHING: pass
        self._urllib_response = NOTHING
        backend.async_request('http://ip.ojii.ch',
                              self.__urllib_async_cb)
        import time
        i = 30
        while self._urllib_response is NOTHING:
            time.sleep(1)
            i -= 1
            if not i:
                break
        self.assertEqual(self._urllib_response.data, self.value)
        

class UtilsSqliteTests(unittest.TestCase):
    def setUp(self):
        from utils import sqlite
        import random
        def gen_steamid():
            return 'STEAM_%s:%s:%s'  % (random.randint(0,9),
                                        random.randint(0,9),
                                        random.randint(10000000,99999999))
        def gen_map():
            prefix = random.choice(['de','cs'])
            length = random.randint(5,40)
            chars  = 'abcdefghijklmnopqrstuvwxyz'
            suffix = ''.join([random.choice(chars) for i in xrange(length)])
            return '%s_%s' % (prefix, suffix)
        
        def get_plays():
            return random.randint(0,100)
        self.sqlite = sqlite
        self.random = random
        # set up legacy database
        con = self._get_con()
        con("""
            CREATE TABLE IF NOT EXISTS players
            (
                id INTEGER PRIMARY KEY AUTOINCREMENT,
                steamid VARCHAR(20) UNIQUE,
                kills INTEGER DEFAULT 0,
                deaths INTEGER DEFAULT 0
            )
            """)
        con("""
            CREATE TABLE IF NOT EXISTS maps
            (
                id INTEGER PRIMARY KEY AUTOINCREMENT,
                mapname VARCHAR(50) UNIQUE
            )
            """)
        con("""
            CREATE TABLE IF NOT EXISTS plays
            (
                player_id INTEGER,
                map_id INTEGER,
                plays INTEGER DEFAULT 0
            )
            """)
        con("""
            CREATE INDEX IF NOT EXISTS player_index ON plays (player_id)
            """)
        con("""
            CREATE INDEX IF NOT EXISTS map_index ON plays (map_id)
            """)
        self.players = [gen_steamid() for i in xrange(1000)]
        for steamid in self.players:
            con("INSERT INTO players (steamid) VALUES (?)", (steamid,))
        self.maps = [gen_map() for i in xrange(50)]
        for mapname in self.maps:
            con("INSERT INTO maps (mapname) VALUES (?)", (mapname,))
        for player in self.players:
            for mapname in self.maps:
                plays = get_plays()
                if plays:
                    con("""
            INSERT INTO plays (player_id, map_id, plays) VALUES
            (
                (SELECT id FROM players WHERE steamid=?),
                (SELECT id FROM maps WHERE mapname=?),
                ?
            )
                        """, (player, mapname, plays))
        con.save()
        con.close()
        
    def _get_con(self):
        return self.sqlite.SimpleConnection('./db.sqlite')
        
    def tearDown(self):
        os.remove('./db.sqlite')
        
    def test_connection(self):
        con = self._get_con()
        self.assertTrue(isinstance(con, self.sqlite.SimpleConnection))
        
    def test_cache(self):
        con = self._get_con()
        cache = self.sqlite.SqlitePKCache(con.cursor,
            "SELECT id FROM players WHERE steamid=?")
        player = self.random.choice(self.players)
        first = cache[player] # will cause the select
        second = cache.cache[player] # will get from cache
        self.assertEqual(first, second)
        
    def test_smart_fetchone(self):
        con = self._get_con()
        player = self.random.choice(self.players)
        con("SELECT id FROM players WHERE steamid=?", (player,))
        row = con.fetchone()
        playerid = row[0]
        self.assertEqual(playerid,
            con.smart_fetchone("SELECT id FROM players WHERE steamid=?",
                               (player,)))
        
    def test_smart_fetchall(self):
        con = self._get_con()
        player = self.random.choice(self.players)
        con("SELECT id,steamid FROM players")
        rows = con.fetchall()
        self.assertEqual(rows,
                         con.smart_fetchall("SELECT id,steamid FROM players"))

        
class UtilsEventsTests(unittest.TestCase):
    def setUp(self):
        from utils import events
        from utils.compat import es
        self.events = events
        self.es = es
        self._testvar = False
        
    def _send_event_cb(self, event_var):
        self._testvar = event_var['hello'] == 'world'
        
    def test_send_event(self):
        self._testvar = False
        self.es.addons.registerForEvent(__import__(__name__), 'unit_test',
                                        self._send_event_cb)
        self.events.send_event('unit_test', {'hello': 'world'})
        self.assertTrue(self._testvar)
        
        
class UtilsTypesTests(unittest.TestCase):
    def setUp(self):
        from utils import types
        self.types = types
        
    def test_auto_dict(self):
        ad = self.types.AutoDict(default=True)
        self.assertTrue(ad['non-existing-key'])
        
    def test_fixed_type_key_dictionary(self):
        ftkd = self.types.FixedTypeKeyDictionary(fixed_type=int)
        ftkd['1'] = 'hello world'
        self.assertEqual(ftkd[1], ftkd['1'])
        
    def test_cached_instances_object(self):
        class CIO(self.types.CachedInstancesObject):
            _named = 'steamid'
            _positional = 0
            def __init__(self, steamid):
                self.steamid = steamid
                
            def init(self, steamid):
                self.steamid = steamid
        p1 = CIO('steam1')
        p2 = CIO('steam1')
        self.assertTrue(p1 is p2)
        
        
class UtilsTerminalTests(unittest.TestCase):
    def setUp(self):
        from utils import terminal
        self.formatter = terminal.TerminalFormatter()
        self.terminal = terminal
        
    def test_terminal_formatter(self):
        self.formatter.add_rule('error', self.terminal.RED)
        self.formatter.add_rule('unformatted', self.terminal.RESET)
        self.formatter.add_pattern('(?P<error>ERR:)(?P<unformatted>.*)')
        formatted = self.formatter.format("ERR: Hello World")
        correct = '\033[31mERR:\033[0m Hello World\033[0m'
        self.assertEqual(formatted, correct)
        

if __name__ == '__main__':
    unittest.main()